/**
 * Copyright (C) 2009-2012, KingHool.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses.
 */
package com.kinghool.smodel;

import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;

import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import com.kinghool.ebos.commons.utils.Assert;
import com.kinghool.smodel.def.XmlModelDefinition;
import com.kinghool.smodel.io.ModelLoader;
import com.kinghool.smodel.io.bean.BeanChannel;
import com.kinghool.smodel.io.bean.IBeanChannelProvider;
import com.kinghool.smodel.io.bean.annotation.AnnotationBeanChannelProvider;
import com.kinghool.smodel.io.json.JsonChannel;
import com.kinghool.smodel.io.json.JsonStreamChannel;
import com.kinghool.smodel.io.source.XmlModelSource;
import com.kinghool.smodel.io.xml.IDocumentProvider;
import com.kinghool.smodel.io.xml.XmlChannel;
import com.kinghool.smodel.io.xml.XmlStringChannel;

/**
 * A facade class for user to handle model related operations
 * 
 * @Author Allen Deng(dengtailin@gmail.com) 
 */
public class ModelService {
    
	 public static IXmlModel loadFromXML(IDocumentProvider provider, XmlModelDefinition... modelDefinition){
		 XmlChannel xmlChannel = new XmlChannel(provider, null);
		 ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(xmlChannel));
	
	     return loader.load((Assert.isNullOrEmpty(modelDefinition) ? null : modelDefinition[0]));
	 }  
	 	 
	 public static IXmlModel loadFromXML(String xmlStr, XmlModelDefinition... modelDefinition){
	     return loadFromXML(new StringReader(xmlStr), modelDefinition);
	 } 
	    
	 public static IXmlModel loadFromXML(final Reader reader, XmlModelDefinition... modelDefinition){
		 return loadFromXML(new IDocumentProvider(){
			public Document getDocument() throws FileNotFoundException, JDOMException, IOException {
				return new SAXBuilder().build(reader);
			}
		 }, modelDefinition);
	 }   
	 
	 public static IXmlModel loadFromXML(final InputStream inputStream, XmlModelDefinition... modelDefinition){
		 return loadFromXML(new IDocumentProvider(){
			public Document getDocument() throws JDOMException, IOException {
				return new SAXBuilder().build(inputStream);
			}
		 }, modelDefinition);
	 }
	 
	 public static void flushToXML(IXmlModel model, String fileName) throws IOException{
		 flushToXML(model, new FileWriter(fileName));
	 }

	 public static void flushToXML(IXmlModel model, OutputStream outputStream){
		 XmlChannel channel = new XmlChannel(null, outputStream);
		 ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
		 loader.flush(model);
	 }
	 
	 public static void flushToXML(IXmlModel model, Writer writer){
		 XmlChannel channel = new XmlChannel(null, writer);
		 ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
		 loader.flush(model);
	 }
	 
	 public static String flushToXML(IXmlModel model){
		 XmlStringChannel channel = new XmlStringChannel();
		 ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
		 loader.flush(model);
		 return channel.getMappedObject();
	 }
	 
	 public static IXmlModel loadFromJSON(String jsonStr, XmlModelDefinition... modelDefinitin){
	     JsonChannel channel = new JsonChannel(jsonStr);
	     ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
	     return loader.load((Assert.isNullOrEmpty(modelDefinitin) ? null : modelDefinitin[0]));
	 } 
	 
	 public static IXmlModel loadFromJSON(InputStream inputStream, XmlModelDefinition... modelDefinitin){
		 JsonStreamChannel channel = new JsonStreamChannel(inputStream, null);
	     ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
	     return loader.load((Assert.isNullOrEmpty(modelDefinitin) ? null : modelDefinitin[0]));
	 }
	 
	 public static IXmlModel loadFromJSON(Reader rdr, XmlModelDefinition... modelDefinitin){
		 JsonStreamChannel channel = new JsonStreamChannel(rdr, null);
	     ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
	     return loader.load((Assert.isNullOrEmpty(modelDefinitin) ? null : modelDefinitin[0]));
	 }
	 
	 public static String flushToJSON(IXmlModel model){
		 JsonChannel channel = new JsonChannel();
	     ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
	     loader.flush(model);
	     return channel.getMappedObject();
	 }
	 
	 public static void flushToJSON(IXmlModel model, String fileName) throws IOException{
		 flushToJSON(model, new FileWriter(fileName));
	 }
	 
	 public static void flushToJSON(IXmlModel model, OutputStream outputStream){
		 flushToJSON(model, new OutputStreamWriter(outputStream));
	 }
	 
	 public static void flushToJSON(IXmlModel model, Writer writer){
		 JsonStreamChannel channel = new JsonStreamChannel(null, writer);
	     ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
	     loader.flush(model);
	 }
	 
	 public static void flushToJSON(IXmlModel model, JsonStreamChannel channel){
	     ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(channel));
	     loader.flush(model);
	 }
	 
	 public static IXmlModel loadFromBean(Object object, XmlModelDefinition... modelDefinitin){
		 IBeanChannelProvider beanChannelProvider = new AnnotationBeanChannelProvider(object.getClass());
		 return loadFromBean(object, beanChannelProvider, modelDefinitin);
	 }
	 
	 public static IXmlModel loadFromBean(Object object, IBeanChannelProvider beanChannelProvider, XmlModelDefinition... modelDefinitin){
		 BeanChannel beanChannel = beanChannelProvider.getBeanChannel();
		 
		 beanChannel.setMappedObject(object);
		 ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(beanChannel));
		 
	     return loader.load((Assert.isNullOrEmpty(modelDefinitin) ? null : modelDefinitin[0]));
	 }
	 	 
	@SuppressWarnings("unchecked")
	public static <T> T flushToBean(IXmlModel model, IBeanChannelProvider beanChannelProvider){
		 BeanChannel beanChannel = beanChannelProvider.getBeanChannel();		 
		 
		 ModelLoader<IXmlModel> loader = new ModelLoader<IXmlModel>(new XmlModelSource(beanChannel)); 
		 loader.flush(model);
		 
		 return (T) beanChannel.getMappedObject();
	 }
}
